package com.chenyue.cm.tecentCloud;

import com.chenyue.cm.live.vo.LiveAddress;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.live.v20180801.LiveClient;
import com.tencentcloudapi.live.v20180801.models.*;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;

import static com.chenyue.cm.tecentCloud.LiveConfig.*;

/**
 * 推拉流生成工具
 */
public class LiveRecordAddressUtils {
    private static final char[] DIGITS_LOWER =
            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    private static Credential credential = null;

    private static LiveClient liveClient = null;

    private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-mm-dd'T'hh:mm:ss'Z'");

    /**
     * 获取推流和拉流地址
     *
     * @param streamName
     * @param txTime
     * @return
     */
    public static LiveAddress getAddressUrl(String streamName, long txTime) {
        String safeUrl = getSafeUrl(streamName, txTime);
        LiveAddress liveAddress = new LiveAddress();
        liveAddress.setPushRTMP("rtmp://" + PUSH_DOMAIN + "/" + APP_NAME + "/" + streamName + "?" + safeUrl);
        liveAddress.setPullRTMP("rtmp://" + PULL_DOMAIN + "/" + APP_NAME + "/" + streamName + "?" + safeUrl);
        liveAddress.setPullFLV("http://" + PULL_DOMAIN + "/" + APP_NAME + "/" + streamName + ".flv" + "?" + safeUrl);
        liveAddress.setPullM3U8("http://" + PULL_DOMAIN + "/" + APP_NAME + "/" + streamName + ".m3u8" + "?" + safeUrl);
        liveAddress.setPullUDP("webrtc://" + PULL_DOMAIN + "/" + APP_NAME + "/" + streamName + "?" + safeUrl);
        return liveAddress;
    }

    /**
     * 实例化认证对象
     *
     * @return
     */
    public static synchronized Credential getCredential() {
        if (credential == null) {
            credential = new Credential(SECRET_ID, SECRET_KEY);
        }
        return credential;
    }

    /**
     * 实例化认证对象
     *
     * @return
     */
    private static LiveClient getLiveClient() {
        if (liveClient == null) {
            liveClient = new LiveClient(getCredential(), "");
        }
        return liveClient;
    }

    /**
     * 禁推 一个直播流 全参数(禁推直播流)
     *
     * @param streamName 直播流名字
     * @param appName    应用名称
     * @param resumeTime 禁推时长（单位分钟）
     * @param reason     禁推原因
     * @return 请求 ID
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static String forbidLiveStream(String streamName, String appName, Long resumeTime, String reason)
            throws TencentCloudSDKException {
        try {
            Long currentTime = System.currentTimeMillis() + resumeTime * 60L * 1000L;
            LiveClient client = getLiveClient();
            ForbidLiveStreamRequest req = new ForbidLiveStreamRequest();
            req.setAppName(appName);
            req.setStreamName(streamName);
            req.setDomainName(PUSH_DOMAIN);
            req.setResumeTime(FORMAT.format(new Date(currentTime)));
            req.setReason(reason);
            ForbidLiveStreamResponse res = client.ForbidLiveStream(req);
            return res.getRequestId();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 禁推 一个直播流
     *
     * @param streamName 直播流名字
     * @param resumeTime 禁推时长（单位分钟）
     * @param reason     禁推原因
     * @return 请求 ID
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static String forbidLiveStream(String streamName, Long resumeTime, String reason) throws TencentCloudSDKException {
        return forbidLiveStream(streamName, APP_NAME, resumeTime, reason);
    }

    /**
     * 禁推 一个直播流 禁推30分钟自动生成
     *
     * @param streamName 直播流名字
     * @param reason     禁推原因
     * @return 请求 ID
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static String forbidLiveStream(String streamName, String reason) throws TencentCloudSDKException {
        return forbidLiveStream(streamName, APP_NAME, 30L, reason);
    }

    /**
     * 查询禁播列表(获取禁推列表)
     *
     * @param PageNum 页数1开始
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static ForbidStreamInfo[] getForbidStreamList(Integer PageNum) throws TencentCloudSDKException {
        try {
            LiveClient client = getLiveClient();
            DescribeLiveForbidStreamListRequest req = new DescribeLiveForbidStreamListRequest();
            req.setPageNum(PageNum.longValue());
            req.setPageSize(10L);
            DescribeLiveForbidStreamListResponse res = client.DescribeLiveForbidStreamList(req);
            return res.getForbidStreamList();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 恢复一个被禁止的直播流 全参数(恢复直播推流)
     *
     * @param streamName 直播流名字
     * @param appName    应用名称
     * @return 请求 ID
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static String resumeLiveStream(String streamName, String appName) throws TencentCloudSDKException {
        try {
            LiveClient client = getLiveClient();
            ResumeLiveStreamRequest req = new ResumeLiveStreamRequest();
            req.setAppName(appName);
            req.setDomainName(PUSH_DOMAIN);
            req.setStreamName(streamName);
            ResumeLiveStreamResponse res = client.ResumeLiveStream(req);
            return res.getRequestId();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 恢复一个被禁止的直播流
     *
     * @param streamName 直播流名字
     * @return 请求 ID
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static String resumeLiveStream(String streamName) throws TencentCloudSDKException {
        return resumeLiveStream(streamName, APP_NAME);
    }

    /**
     * 暂停一个直播流 全参数（断开直播推流）
     * 当某些原因暂停主播继续推流时，可调用此接口
     * 默认接口请求频率限制：100次/秒
     *
     * @param streamName 直播流名字
     * @param appName    应用名称
     * @return 请求 ID
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static String dropLiveStream(String streamName, String appName) throws TencentCloudSDKException {
        try {
            LiveClient client = getLiveClient();
            DropLiveStreamRequest req = new DropLiveStreamRequest();
            req.setAppName(appName);
            req.setDomainName(PUSH_DOMAIN);
            req.setStreamName(streamName);
            DropLiveStreamResponse res = client.DropLiveStream(req);
            return res.getRequestId();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 暂停一个直播流 全参数
     *
     * @param streamName 直播流名字
     * @return 请求 ID
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static String dropLiveStream(String streamName) throws TencentCloudSDKException {
        return dropLiveStream(streamName, APP_NAME);
    }

    /**
     * 正在直播中的流列表（查询直播中的流）
     *
     * @param PageNum    页码
     * @param streamName 直播流名字
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static StreamOnlineInfo[] describeLiveStreamOnlineList(Integer PageNum, String streamName)
            throws TencentCloudSDKException {
        try {
            LiveClient client = getLiveClient();
            DescribeLiveStreamOnlineListRequest req = new DescribeLiveStreamOnlineListRequest();
            req.setAppName(APP_NAME);
            req.setStreamName(streamName);
            req.setPageNum(PageNum.longValue());
            req.setPageSize(10L);
            DescribeLiveStreamOnlineListResponse res = client.DescribeLiveStreamOnlineList(req);
            return res.getOnlineInfo();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * （查询历史流列表）
     *
     * @param pageNum    页码
     * @param pageSize   分页大小
     * @param streamName 直播流名字
     * @param StartTime  起始时间 最长支持查询60天内数据
     * @param EndTime    结束时间 EndTime和StartTime相差不可超过30天。
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static StreamName[] describeLiveStreamPublishedList(Integer pageNum, Integer pageSize, String streamName, String StartTime, String EndTime)
            throws TencentCloudSDKException {
        try {
            LiveClient client = getLiveClient();
            DescribeLiveStreamPublishedListRequest req = new DescribeLiveStreamPublishedListRequest();
            req.setAppName(APP_NAME);
            req.setStreamName(streamName);
            req.setPageNum(pageNum.longValue());
            req.setPageSize(pageSize.longValue());
            req.setDomainName(PUSH_DOMAIN);
            req.setStartTime(StartTime);
            req.setEndTime(EndTime);
            DescribeLiveStreamPublishedListResponse res = client.DescribeLiveStreamPublishedList(req);
            return res.getPublishInfo();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * （查询流状态）
     *
     * @param streamName 直播流名字
     * @return
     * @throws TencentCloudSDKException
     */
    public static String describeLiveStreamPublishedList(String streamName) {
        try {
            LiveClient client = getLiveClient();
            DescribeLiveStreamStateRequest req = new DescribeLiveStreamStateRequest();
            req.setAppName(APP_NAME);
            req.setStreamName(streamName);
            req.setDomainName(PUSH_DOMAIN);
            DescribeLiveStreamStateResponse res = client.DescribeLiveStreamState(req);
            return DescribeLiveStreamStateResponse.toJsonString(res);
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        System.err.println(getAddressUrl("10002", 1634000400));
        System.err.println(Integer.parseInt("6164DE10", 16));
//        System.err.println(1634000400 - (System.currentTimeMillis() / 1000));
    }

    /**
     * (查询推断流事件)
     *
     * @param StartTime  起始时间。起始时间
     * @param EndTime    结束时间 不超过当前时间，且和起始时间相差不得超过30天
     * @param streamName 流名称 使用IsStrict字段改为精确查询
     * @param pageNum    取得第几页
     * @param pageSize   分页大小
     * @param isFilter   是否过滤，默认不过滤
     * @param isStrict   是否精确查询，默认模糊匹配。 0：模糊匹配。1：精确查询
     * @param isAsc      是否按结束时间正序显示，默认逆序
     * @return
     * @throws TencentCloudSDKException
     */
    public static StreamEventInfo[] describeLiveStreamEventList(String StartTime, String EndTime, String streamName, Integer pageNum, Integer pageSize, Integer isFilter, Integer isStrict, Integer isAsc)
            throws TencentCloudSDKException {
        try {
            LiveClient client = getLiveClient();
            DescribeLiveStreamEventListRequest req = new DescribeLiveStreamEventListRequest();
            req.setStartTime(StartTime);
            req.setEndTime(EndTime);
            req.setAppName(APP_NAME);
            req.setDomainName(PUSH_DOMAIN);
            req.setStreamName(streamName);
            req.setPageNum(pageNum.longValue());
            req.setPageSize(pageSize.longValue());
            req.setIsFilter(isFilter.longValue());
            req.setIsStrict(isStrict.longValue());
            req.setIsAsc(isAsc.longValue());
            DescribeLiveStreamEventListResponse res = client.DescribeLiveStreamEventList(req);
            return res.getEventList();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询播放数据，支持按流名称查询详细播放数据，也可按播放域名查询详细总数据（统计查询相关接口-查询流的播放信息列表）
     *
     * @param streamName 直播流名字
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static DayStreamPlayInfo[] describeStreamPlayInfoList(String streamName, String StartTime, String EndTime)
            throws TencentCloudSDKException {
        try {
            LiveClient client = getLiveClient();
            DescribeStreamPlayInfoListRequest req = new DescribeStreamPlayInfoListRequest();
            req.setStreamName(streamName);
            req.setStartTime(StartTime);
            req.setEndTime(EndTime);
            DescribeStreamPlayInfoListResponse res = client.DescribeStreamPlayInfoList(req);
            return res.getDataInfoList();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询天维度每条流的播放数据，包括总流量等（统计查询相关接口-查询所有流的流量数据）
     *
     * @param DayTime 日期， 格式：YYYY-mm-dd。
     * @throws TencentCloudSDKException
     * @author hl128k
     */
    public static PlayDataInfoByStream[] describeStreamDayPlayInfoList(String DayTime) throws TencentCloudSDKException {
        try {
            LiveClient client = getLiveClient();
            DescribeStreamDayPlayInfoListRequest req = new DescribeStreamDayPlayInfoListRequest();
            req.setDayTime(DayTime);
            DescribeStreamDayPlayInfoListResponse res = client.DescribeStreamDayPlayInfoList(req);
            return res.getDataInfoList();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }

    /*
     * KEY+ streamName + txTime
     */
    private static String getSafeUrl(String streamName, long txTime) {
//        处理过期时间  （旧版本过期时间传秒 新版本 传日期时间戳 需手动转换）
        txTime = System.currentTimeMillis() / 1000 + txTime;
        String input = LiveConfig.PUSH_KEY + streamName + Long.toHexString(txTime).toUpperCase();

        String txSecret = null;
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            txSecret = byteArrayToHexString(
                    messageDigest.digest(input.getBytes(StandardCharsets.UTF_8)));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        return txSecret == null ? "" :
                "txSecret=" +
                        txSecret +
                        "&" +
                        "txTime=" +
                        Long.toHexString(txTime).toUpperCase();
    }

    private static String byteArrayToHexString(byte[] data) {
        char[] out = new char[data.length << 1];

        for (int i = 0, j = 0; i < data.length; i++) {
            out[j++] = DIGITS_LOWER[(0xF0 & data[i]) >>> 4];
            out[j++] = DIGITS_LOWER[0x0F & data[i]];
        }
        return new String(out);
    }
}
